<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>星级评分原理和实现--点亮半颗星星</title>
    <link rel="stylesheet" type="" href="css/main.css">
</head>
<body>
    <ul id="rating" class="rating">
        <li class="rating_item" title="很不好"></li> 
        <li class="rating_item" title="不好"></li> 
        <li class="rating_item" title="一般"></li> 
        <li class="rating_item" title="好"></li> 
        <li class="rating_item" title="很好"></li> 
    </ul>
    
    <ul id="rating2" class="rating">
        <li class="rating_item" title="很不好"></li> 
        <li class="rating_item" title="不好"></li> 
        <li class="rating_item" title="一般"></li> 
        <li class="rating_item" title="好"></li> 
        <li class="rating_item" title="很好"></li> 
    </ul>

    <script src="js/jquery-3.2.1.min.js"></script>
    <script>

        //减少暴露全局变量，引入局部作用域
        var rating = (function() {

            //点亮整颗
            var LightEntire = function(el, options) {
                this.$el = $(el);   //变成jQuery对象
                this.$item = this.$el.find('.rating_item');
                this.opts = options;
            };

            //初始化方法，一般都是：将方法写在构造函数的原型上，这样写可以保证不管你实例化多少次，我们内存中都只有一份
            LightEntire.prototype.init = function() {
                this.lightOn(this.opts.num);    //点亮几颗星星

                //判断是否只读
                if(!this.opts.readOnly) {
                    this.bindEvent();               //绑定事件
                }
                
            };

            LightEntire.prototype.lightOn = function(num) {
                num = parseInt(num);    //转化成整数

                this.$item.each(function(index){
                    if(index < num) {
                        $(this).css('background-position','0 -65px');
                    } else {
                        $(this).css('background-position','0 0');
                    }
                });
            };

            LightEntire.prototype.bindEvent = function() {
                var self = this,
                    itemLength = self.$item.length;

                self.$el.on('mouseover', '.rating_item', function() {
                    var num = $(this).index() + 1

                    self.lightOn( num );

                    //判断select是否为函数
                    (typeof self.opts.select === 'function') && self.opts.select.call( this, num, itemLength );

                    // 触发事件
                    self.$el.trigger('select',[num,itemLength]);

                }).on('click', '.rating_item', function() {
                    self.opts.num = $(this).index() +1;

                    //判断select是否为函数
                    (typeof self.opts.chosen === 'function') && self.opts.chosen.call( this, self.opts.num, itemLength );

                    // 触发事件
                    self.$el.trigger('chosen',[self.opts.num,itemLength]);

                }).on('mouseout',function() {
                    self.lightOn(self.opts.num);
                });
            };

            // 默认参数
            var defaults = {
                num:0,                  //默认点亮的星星个数
                readOnly:false,         //是否自读
                select:function() {},   //鼠标每次移到星星的时候执行的方法
                chosen:function() {}    //点击星星的时候
            }

            //初始化
            var init = function(el,options) {
                options = $.extend({}, defaults, options);         // $.extend() 函数用于将一个或多个对象的内容合并到目标对象,这里是用options的内容来覆盖defaults的内容，生成的内容放到{}这个空对象中
                new LightEntire(el,options).init();       //实例化LightEntire(),调用init()方法
            };

            // 返回对象，有返回就需要在外部引入一个全局变量来接受它，就是var rating
            return {
                init:init
            };
        })();

        // 用rating的init方法来调用，第一个参数是评分的ID,第二个是对象
        rating.init('#rating',{
            num:2,
            // select:function(num, total) {
            //     console.log(this);
            //     console.log(num + '/' + total);
            // },
        });

        // 绑定事件
        $('#rating').on('select',function(el, num, total) {
            console.log(num + '/' + total);
        }).on('chosen',function(e, num, total) {
            console.log(num + '/' + total);
        });


        // // 改进代码2 => 闭包：自我执行函数
        // var rating = (function(){

        //     //点亮
        //     var lightOn = function($item,num) {
        //         $item.each(function(index){
        //             if(index < num) {
        //                 $(this).css('background-position','0 -65px');
        //             } else {
        //                 $(this).css('background-position','0 0');
        //             }
        //         });
        //     };

        //     // 改进代码3 => 代码复用:用函数传递参数
        //     var init = function(el,num) {
        //         var $rating = $(el),
        //             $item = $rating.find('.rating_item');

        //         //初始化 
        //         lightOn($item,num);

        //         //事件绑定---改进代码1 => 事件委托：子元素委托给父元素(降低浏览器的性能需求)
        //         $rating.on('mouseover', '.rating_item', function() {
        //             lightOn($item, $(this).index() + 1 );
        //         }).on('click', '.rating_item', function() {
        //             num = $(this).index() +1;
        //         }).on('mouseout',function() {
        //             lightOn($item,num);
        //         });

        //     };

        //     //改进代码3 => jQuery插件
        //     $.fn.extend({
        //         rating:function(num) {
        //             return this.each(function() {
        //                 init(this,num)
        //             });
        //         }
        //     });

        //     // 返回个对象
        //     return {
        //         init:init
        //     };

        // })(); 

        // rating.init('#rating',2);
        // // rating.init('#rating2',3);

        // //插件调用
        // $('#rating2').rating(4)

    </script>
</body>
</html>